#include <iostream>
#include <fstream>
#include <stdio.h>
#include <string.h>
#include <map>
#include <vector>
#include <dirent.h>
#include <algorithm>
#include <pthread.h>
#include <ThostFtdcTraderApi.h>
#include <json.hpp>
#include "Tester.h"
#include "Struct.h"
using namespace std;

pthread_cond_t doneCond; 
pthread_mutex_t doneMutex; 

extern pthread_cond_t doneCond; 
extern pthread_mutex_t doneMutex; 

int main(int argc, char *argv[], char **env)
{
	fprintf(stderr,"usage:\n");
	fprintf(stderr,"'a':\tshow account info\n");
	fprintf(stderr,"'t':\tsingle instrument manual trade\n");
	fprintf(stderr,"'m':\tcheckout instrument info\n");
	fprintf(stderr,"'p':\tshow positions\n");
	fprintf(stderr,"'o':\tshow orders\n");
	fprintf(stderr,"'c':\tcancel all orders\n");
	fprintf(stderr,"'q':\tquit\n");
	std::string USER="user.json";
	if(argc>1)
		USER=argv[1];
	ifstream in;
	in.open(USER.c_str());
    string content((istreambuf_iterator<char>(in)), istreambuf_iterator<char>());
	in.close();
	nlohmann::json config = nlohmann::json::parse(content);
	char TD_FRONT[64],BROKER_ID[64],INVESTOR_ID[64],PASSWORD[64],APPID[64],AUTHCODE[64];
	strcpy(TD_FRONT, config["TD_FRONT"].get<string>().c_str());
	strcpy(INVESTOR_ID, config["INVESTOR_ID"].get<string>().c_str());
	strcpy(BROKER_ID, config["BROKER_ID"].get<string>().c_str());
	strcpy(PASSWORD,  config["PASSWORD"].get<string>().c_str());
	strcpy(APPID,     config["APPID"].get<string>().c_str());
	strcpy(AUTHCODE,  config["AUTHCODE"].get<string>().c_str());


	Tester* tradeSpi=new Tester();
	CThostFtdcTraderApi* tradeAPI = CThostFtdcTraderApi::CreateFtdcTraderApi("./");	
	tradeAPI->RegisterSpi(tradeSpi);
	tradeAPI->RegisterFront(TD_FRONT);
	tradeAPI->SubscribePublicTopic(THOST_TERT_QUICK);
	tradeAPI->SubscribePrivateTopic(THOST_TERT_QUICK);
	pthread_mutex_lock(&doneMutex);	
	tradeAPI->Init();
	pthread_cond_wait (&doneCond, &doneMutex); 
	pthread_mutex_unlock (&doneMutex); 

	int iRequestID=0,result=0;
	/* Authorize */
	CThostFtdcReqAuthenticateField authField;
	memset(&authField, 0, sizeof(authField));
	strcpy(authField.BrokerID, BROKER_ID);
	strcpy(authField.UserID, INVESTOR_ID);
	strcpy(authField.AppID, APPID);
	strcpy(authField.AuthCode, AUTHCODE);
	pthread_mutex_lock(&doneMutex);
	tradeAPI->ReqAuthenticate(&authField, ++iRequestID);
	pthread_cond_wait (&doneCond, &doneMutex); 
	pthread_mutex_unlock (&doneMutex); 

	/* Login */
	CThostFtdcReqUserLoginField req;
	memset(&req, 0, sizeof(req));
	strcpy(req.BrokerID, BROKER_ID);
	strcpy(req.UserID, INVESTOR_ID);
	strcpy(req.Password, PASSWORD);
	pthread_mutex_lock(&doneMutex);
	tradeAPI->ReqUserLogin(&req, ++iRequestID);	
	pthread_cond_wait (&doneCond, &doneMutex); 
	pthread_mutex_unlock (&doneMutex); 
/*
		char pSystemInfo[344];
		int len;
		CTP_GetSystemInfo(pSystemInfo, len);

		CThostFtdcUserSystemInfoField a = { 0 };
		strcpy_s(a.BrokerID, g_chBrokerID);
		strcpy_s(a.UserID, g_chUserID);
		memcpy(a.ClientSystemInfo, pSystemInfo, len);
		a.ClientSystemInfoLen = len;

		strcpy_s(a.ClientPublicIP, "139.196.6.156");
		a.ClientIPPort = 51305;
		strcpy_s(a.ClientLoginTime, "20190613");
		strcpy_s(a.ClientAppID, "client_861352_1.0");
		tradeApi->RegisterUserSystemInfo(&a);
*/
	/* Confirm SettlementInfo */
	CThostFtdcSettlementInfoConfirmField req1;
	memset(&req1, 0, sizeof(req1));
	strcpy(req1.BrokerID, BROKER_ID);
	strcpy(req1.InvestorID, INVESTOR_ID);
	pthread_mutex_lock(&doneMutex);
	result=tradeAPI->ReqSettlementInfoConfirm(&req1, ++iRequestID);
	pthread_cond_wait (&doneCond, &doneMutex); 
	pthread_mutex_unlock (&doneMutex); 
/*
	CThostFtdcQryInstrumentField req4;
	memset(&req4, 0, sizeof(req4));
	pthread_mutex_lock(&doneMutex);
	tradeAPI->ReqQryInstrument(&req4, ++iRequestID);
	pthread_cond_wait (&doneCond, &doneMutex); 
	pthread_mutex_unlock (&doneMutex);		
*/
	char cmd='a';
	while(1)
	{
		switch(cmd)
		{
			case 'q':
			{
				exit(1);				
			}
			case 'p':
			{
				CThostFtdcQryInvestorPositionDetailField req2;
				memset(&req2, 0, sizeof(req2));
				strcpy(req2.BrokerID, BROKER_ID);
				strcpy(req2.InvestorID, INVESTOR_ID);			
				pthread_mutex_lock(&doneMutex);
				cerr<<(tradeAPI->ReqQryInvestorPositionDetail(&req2, ++iRequestID)==0?"":"fail\n");
				pthread_cond_wait (&doneCond, &doneMutex); 
				pthread_mutex_unlock (&doneMutex); 
				break;
			}
			case 'o':
			{
				CThostFtdcQryOrderField req3;
				memset(&req3, 0, sizeof(req3));
				strcpy(req3.BrokerID, BROKER_ID);
				strcpy(req3.InvestorID, INVESTOR_ID);
				pthread_mutex_lock(&doneMutex);	
				cerr<<(tradeAPI->ReqQryOrder(&req3, ++iRequestID)==0?"":"fail\n");
				pthread_cond_wait (&doneCond, &doneMutex); 
				pthread_mutex_unlock (&doneMutex); 

				break;

			}
			case 'a':
			{				
				CThostFtdcQryTradingAccountField req;
				memset(&req, 0, sizeof(req));
				strcpy(req.BrokerID, BROKER_ID);
				strcpy(req.InvestorID, INVESTOR_ID);			
				pthread_mutex_lock(&doneMutex);
				tradeAPI->ReqQryTradingAccount(&req, ++iRequestID);	
				pthread_cond_wait (&doneCond, &doneMutex); 
				pthread_mutex_unlock (&doneMutex);			 
				break;
			}
			case 'm':
			{

				cerr<<"instrument id?"<<endl;
				TThostFtdcInstrumentIDType instru;
				cin>>instru;
				CThostFtdcQryInstrumentMarginRateField req;
				memset(&req, 0, sizeof(req));
				strcpy(req.BrokerID, BROKER_ID);
				strcpy(req.InvestorID, INVESTOR_ID);			
				strcpy(req.InstrumentID,instru);
				req.HedgeFlag='1';
				pthread_mutex_lock(&doneMutex);
				tradeAPI->ReqQryInstrumentMarginRate(&req, ++iRequestID);
				pthread_cond_wait (&doneCond, &doneMutex); 
				pthread_mutex_unlock (&doneMutex);
 
				CThostFtdcQryInstrumentCommissionRateField req1;
				memset(&req1, 0, sizeof(req1));
				strcpy(req1.BrokerID, BROKER_ID);
				strcpy(req1.InvestorID, INVESTOR_ID);			
				strcpy(req1.InstrumentID,instru);
	
				pthread_mutex_lock(&doneMutex);
				tradeAPI->ReqQryInstrumentCommissionRate(&req1,   ++iRequestID);
				pthread_cond_wait (&doneCond, &doneMutex); 
				pthread_mutex_unlock (&doneMutex);			 

				break;
			}
			case 't':
			{
				TThostFtdcInstrumentIDType instru;
				cerr<<"instrument id?"<<endl;
				cin>>instru;
				char close,sell;
				double limitPrice;
				int volume,id;

				cerr<<"==== "<<instru<<" ====\nid Close(1)/CloseToday(3)/open(0) sell(1)/buy(0) volume price"<<endl;
				int ignore=scanf("%d %c %c %d %lf",&id,&close,&sell,&volume,&limitPrice);


				CThostFtdcInputOrderField req;
				memset(&req, 0, sizeof(req));
				req.OrderPriceType = THOST_FTDC_OPT_LimitPrice;
				req.CombHedgeFlag[0] = THOST_FTDC_HF_Speculation;	
				req.TimeCondition = THOST_FTDC_TC_GFD;///有效期类型: 当日有效	
				req.VolumeCondition = THOST_FTDC_VC_AV;///成交量类型: 任何数量	
				req.MinVolume = 1;///最小成交量: 1	
				req.ContingentCondition = THOST_FTDC_CC_Immediately;///触发条件: 立即	
				req.ForceCloseReason = THOST_FTDC_FCC_NotForceClose;///强平原因: 非强	
				req.IsAutoSuspend = 1;///自动挂起标志: 是	
				req.UserForceClose = 0;///用户强评标志: 否
				strcpy(req.BrokerID, BROKER_ID);
				strcpy(req.InvestorID, INVESTOR_ID);
				strcpy(req.InstrumentID, instru);
				req.Direction = sell;
				req.CombOffsetFlag[0] = close;
				req.LimitPrice = limitPrice;
				req.VolumeTotalOriginal = volume;
				cout<<(req.Direction=='0'?"Buy":"Sell")<<(req.CombOffsetFlag[0]=='0'?"Open":"Close")<<" "<<req.InstrumentID<<" "<<req.VolumeTotalOriginal<<"@"<<req.LimitPrice<<endl;
				iRequestID++;
				strcpy(req.OrderRef , to_string(id).c_str());
				tradeAPI->ReqOrderInsert(&req, iRequestID);
				break;
			}
			case 'c':
			{

				for(map<string,string>::iterator it=tradeSpi->order.begin();it!=tradeSpi->order.end();it++)
				{

					string k=it->first;
					size_t i= k.find("|");

					CThostFtdcInputOrderActionField req;
					memset(&req, 0, sizeof(req));
					strcpy(req.BrokerID, BROKER_ID);
					strcpy(req.InvestorID, INVESTOR_ID);
					req.ActionFlag = THOST_FTDC_AF_Delete;
					strcpy(req.ExchangeID,k.substr(0,i).c_str());
					strcpy(req.OrderSysID,k.substr(i+1,k.size()-i-1).c_str());
					cout<<"cancel "<<req.OrderSysID<<" "<<req.ExchangeID<<"\n";
					tradeAPI->ReqOrderAction(&req, ++iRequestID);
				}				
//				cerr<<"orders cancelled\n";
				break;
			}
			default:{}
		}
		cin>>cmd;

		
	}
	return 0;
}
